package com.zb.file.servlet;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

public class FileServlet extends HttpServlet {

    /*ServletFileUpload负责处理上传的文件数据,并将表单中每个输入顶封装成一个FiLeItem对象,
    在使用ServletFileUpload对象解析请求时需要DiskFiLeItemFactory对象. 所以,我们需要在进行解析工作前构造DiskFiLeItemFactory对象,
    通过ServletFileUpload对象的构造方法或setFiLeItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性. */

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html");
        if(!ServletFileUpload.isMultipartContent(req)){//表单中是否包含文件
            return;
        }

        //创建存储文件的路径，放在WEB-INF下，安全，无法直接通过url访问
        String uploadPath = this.getServletContext().getRealPath("WEB-INF/upload");
        File uploadFile = new File(uploadPath);
        if(!uploadFile.exists()){
            uploadFile.mkdir();
        }

        //如果文件过大，我们应当创建临时文件路径，并定期做清除，或提醒用户转为永久文件
        String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp");
        File tmpFile = new File(tmpPath);
        if (!tmpFile.exists()){
            tmpFile.mkdir();
        }

        //处理上传的文件，一般都需要通过流来获取，我们可以使用request.getInputStream()，原生态的文件上传流获取，十分麻烦
        //但是我们都建议使用Apache的文件上传组件来实现，common-fileUpload，它需要依赖于commons-io组件
        //req.getInputStream()

        //1.创建 DiskFileItemFactory 对象，设置缓存大小，超过这个大小会放到临时目录
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        diskFileItemFactory.setSizeThreshold(1024 * 1024); //缓存大小为1M
        diskFileItemFactory.setRepository(tmpFile); //设置临时目录

        //2.创建 ServletFileUpload 对象，传递 磁盘文件工厂对象
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
        //监听上传进度
        servletFileUpload.setProgressListener(new ProgressListener() {
            /*
                pBytesRead：已经读取到的文件大小
                pContentLength：文件大小
             */
            @Override
            public void update(long pBytesRead, long pContentLength, int pItems) {
                System.out.println("总大小：" + pContentLength + ", 已读取大小：" + pBytesRead);
            }
        });

        //设置文件编码
        servletFileUpload.setHeaderEncoding("UTF-8");
        //设置单个文件最大值
        servletFileUpload.setFileSizeMax(1024 * 1024 * 10);
        //设置总共能上传的文件大小
        servletFileUpload.setSizeMax(1024 * 1024 * 10);

        //3.处理上传文件
        try {
            List<FileItem> fileItems = servletFileUpload.parseRequest(req);
            for (FileItem fileItem : fileItems) {
                if(fileItem.isFormField()){//普通表单，非文件
                    String fieldName = fileItem.getFieldName();
                    String filedValue = fileItem.getString("UTF-8");//处理乱码
                    System.out.println(fieldName + ":" + filedValue);
                }else {
                    //=======================处理文件==============================//
                    String fileItemName = fileItem.getName();
                    //判断文件名是否合法
                    if(null == fileItemName || "".equals(fileItemName.trim())){
                        continue;
                    }
                    //获得上传文件名 /images/xxx/xxx.png
                    String fileName = fileItemName.substring(fileItemName.lastIndexOf("/") + 1);
                    //获得上传文件的后缀名
                    String fileType = fileItemName.substring(fileItemName.lastIndexOf(".") + 1);
                    System.out.println("文件信息：文件名-" + fileName + "，文件类型-" + fileType);

                    //=======================存放目录==============================//
                    //这里不修改文件名，而是给每个文件都放一个新的目录，目录名为uuid
                    String uuidPath = UUID.randomUUID().toString();
                    String realPath = uploadPath + "/" + uuidPath;
                    File file = new File(realPath);
                    if(!file.exists()){
                        file.mkdir();
                    }

                    //=======================文件传输==============================//
                    InputStream fileItemInputStream = fileItem.getInputStream();

                    FileOutputStream fileOutputStream = new FileOutputStream(realPath + "/" + fileName);
                    byte[] bytes = new byte[1024 * 1024];

                    int len = 0;
                    while ((len = fileItemInputStream.read(bytes)) != -1){
                        fileOutputStream.write(bytes , 0, len);
                    }

                    fileOutputStream.close();
                    fileItemInputStream.close();
                    fileItem.delete(); //上传成功清除临时文件

                    System.out.println("文件上传成功");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            req.setAttribute("msg", "fail！");
            req.getRequestDispatcher("index.jsp").forward(req, resp);
        }

        req.setAttribute("msg", "success！");
        req.getRequestDispatcher("index.jsp").forward(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
